/**
 * typeofit.js - Using typeofit.js to get the real JavaScript type of a value.
 *
 * @copyright Copyright (c) 2017 Robert Yao
 * @author Robert Yao
 * @update 2017-07-11
 * @licence MIT
 */
(function () {
    'use strict';

    var global = typeof window !== 'undefined' ? window : this,
        OP = Object.prototype,
        toString = OP.toString,
        TYPE_BOOLEAN = 'boolean',
        TYPE_NULL = 'null',
        TYPE_UNDEFINED = 'undefined',
        TYPE_NUMBER = 'number',
        TYPE_STRING = 'string',
        TYPE_OBJECT = 'object',
        TYPE_ARRAY = 'array',
        TYPE_ARRAY_BUFFER = 'arraybuffer',
        TYPE_DATA_VIEW = 'dataview',
        TYPE_DATE = 'date',
        TYPE_ERROR = 'error',
        TYPE_ARGUMENTS = 'arguments',
        TYPE_COLLECTION = 'collection',
        TYPE_FUNCTION = 'function',
        TYPE_ELEMENT = 'element',
        TYPE_TEXT = 'text',
        TYPE_WHITESPACE = 'whitespace',
        TYPE_REGEXP = 'regexp',
        TYPE_SYMBOL = 'symbol',
        TYPE_SET = 'set',
        TYPE_WEAKSET = 'weakset',
        TYPE_MAP = 'map',
        TYPE_WEAKMAP = 'weakmap',
        TYPE_INT8_ARRAY = 'int8array',
        TYPE_UNIT8_ARRAY = 'uint8array',
        TYPE_UNIT8_CLAMPED_ARRAY = 'uint8clampedarray',
        TYPE_INT16_ARRAY = 'int16array',
        TYPE_UNIT16_ARRYA = 'uint16array',
        TYPE_INT32_ARRAY = 'int32array',
        TYPE_UNIT32_ARRAY = 'uint32array',
        TYPE_FLOAT32_ARRAY = 'float32array',
        TYPE_FLOAT64_ARRAY = 'float64array',
        OBJECT_ARRAY = '[object Array]',
        OBJECT_ARRAY_BUFFER = '[object ArrayBuffer]',
        OBJECT_INT8_ARRAY = '[object Int8Array]',
        OBJECT_UNIT8_ARRAY = '[object Uint8Array]',
        OBJECT_UNIT8_CLAMPED_ARRAY = '[object Uint8ClampedArray]',
        OBJECT_INT16_ARRAY = '[object Int16Array]',
        OBJECT_UNIT16_ARRAY = '[object Uint16Array]',
        OBJECT_INT32_ARRAY = '[object Int32Array]',
        OBJECT_UNIT32_ARRAY = '[object Uint32Array]',
        OBJECT_FLOAT32_ARRAY = '[object Float32Array]',
        OBJECT_FLOAT64_ARRAY = '[object Float64Array]',
        OBJECT_DATA_VIEW = '[object DataView]',
        OBJECT_DATE = '[object Date]',
        OBJECT_ERROR = '[object Error]',
        OBJECT_FUNCTION = '[object Function]',
        OBJECT_REGEXP = '[object RegExp]',
        OBJECT_SET = '[object Set]',
        OBJECT_WEAKSET = '[object WeakSet]',
        OBJECT_MAP = '[object Map]',
        OBJECT_WEAKMAP = '[object WeakMap]',
        OBJECT_SYMBOL = '[object Symbol]',
        REGEXP_BASE64 = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/,
        REGEXP_HEX = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;

    /**
     * @method typeOf
     * @param {*} val - 要检测的任意值
     * @returns {String}
     */
    function typeOf ( val ) {
        var type = toString.apply( val );

        /* ===== 原始值类型（Primitive data types） ===== */
        // 检查是否为 Boolean 类型
        if ( typeof val === TYPE_BOOLEAN ) {
            return TYPE_BOOLEAN;
        }

        // 检测是否为 null
        if ( val === null ) {
            return TYPE_NULL;
        }

        // 检测是否为 Number 类型
        if ( typeof val === TYPE_NUMBER && isFinite( val ) ) {
            return TYPE_NUMBER;
        }

        // 检测是否为 Undefined
        if ( typeof val === TYPE_UNDEFINED ) {
            return TYPE_UNDEFINED;
        }

        // 检测是否为 String 类型
        if ( typeof val === TYPE_STRING ) {
            return TYPE_STRING;
        }

        /* ===== ES6 ( Map, WeakMap, Set, WeakSet, Symbol ) ===== */
        // 检测是否为 Set 类型
        if ( type === OBJECT_SET ) {
            return TYPE_SET;
        }

        // 检测是否为 WeakSet 类型
        if ( type === OBJECT_WEAKSET ) {
            return TYPE_WEAKSET;
        }

        // 检测是否为 Map 类型
        if ( type === OBJECT_MAP ) {
            return TYPE_MAP;
        }

        // 检测是否为 WeakMap 类型
        if ( type === OBJECT_WEAKMAP ) {
            return TYPE_WEAKMAP;
        }

        // 检测是否为 Symbol 类型
        if ( type === OBJECT_SYMBOL ) {
            return TYPE_SYMBOL;
        }

        /* ===== 引用类型（Reference data types） ===== */
        // 检测是否为 Array 类型
        if ( type === OBJECT_ARRAY ) {
            return TYPE_ARRAY;
        }

        // 检测是否为 ArrayBuffer 类型
        if ( type === OBJECT_ARRAY_BUFFER ) {
            return TYPE_ARRAY_BUFFER;
        }

        // 检测是否为 DataView 类型
        if ( type === OBJECT_DATA_VIEW ) {
            return TYPE_DATA_VIEW;
        }

        // 检测是否为 Date 类型
        if ( type === OBJECT_DATE ) {
            return TYPE_DATE;
        }

        // 检测是否为 Error 类型
        if ( type === OBJECT_ERROR ) {
            return TYPE_ERROR;
        }

        // 检测是否为 Function 类型
        if ( (typeof val === TYPE_FUNCTION) || type === OBJECT_FUNCTION ) {
            return TYPE_FUNCTION;
        }

        // 检测是否为 RegExp 类型
        if ( type === OBJECT_REGEXP ) {
            return TYPE_REGEXP;
        }

        /* ===== ES2017 Arrays ===== */
        // Int - 整数
        // Uint - 无符号整数
        // Float - IEEE754 浮点数
        if ( type === OBJECT_INT8_ARRAY ) {
            return TYPE_INT8_ARRAY;
        }

        if ( type === OBJECT_UNIT8_ARRAY ) {
            return TYPE_UNIT8_ARRAY;
        }

        if ( type === OBJECT_UNIT8_CLAMPED_ARRAY ) {
            return TYPE_UNIT8_CLAMPED_ARRAY;
        }

        if ( type === OBJECT_INT16_ARRAY ) {
            return TYPE_INT16_ARRAY;
        }

        if ( type === OBJECT_UNIT16_ARRAY ) {
            return TYPE_UNIT16_ARRYA;
        }

        if ( type === OBJECT_INT32_ARRAY ) {
            return TYPE_INT32_ARRAY;
        }

        if ( type === OBJECT_UNIT32_ARRAY ) {
            return TYPE_UNIT32_ARRAY;
        }

        if ( type === OBJECT_FLOAT32_ARRAY ) {
            return TYPE_FLOAT32_ARRAY;
        }

        if ( type === OBJECT_FLOAT64_ARRAY ) {
            return TYPE_FLOAT64_ARRAY;
        }

        /* ===== 其它类型（Others） ===== */
        // 检测是否为一个 DOM
        if ( val.nodeName ) {

            // 检测是否为 Element 节点
            if ( val.nodeType === 1 ) {
                return TYPE_ELEMENT;
            }

            // 检测是否为 Text 节点
            if ( val.nodeType === 3 ) {
                return (/\S/).test( val.nodeValue ) ? TYPE_TEXT : TYPE_WHITESPACE;
            }
        }
        else {

            // 检测是否为 ArrayLike 类型
            if ( typeof val === TYPE_OBJECT && typeof val.length === TYPE_NUMBER && val.length > 0 ) {

                // 检测是否为 Arguments 类型
                if ( 'callee' in val ) {
                    return TYPE_ARGUMENTS;
                }

                // 检测是否为 NodeList 类型
                if ( 'item' in val ) {
                    return TYPE_COLLECTION;
                }
            }
        }

        // 其它标准的数据类型
        return typeof val;
    }

    /**
     * 检测测试数据是否为 Array 类型
     *
     * @method isArray
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Array 则返回 true，否则返回 false
     */
    function isArray ( val ) {
        return Array.isArray ? Array.isArray( val ) : typeOf( val ) === TYPE_ARRAY;
    }

    /**
     * 检测测试数据的数据类型是否为类似数组（array、arguments 对象或者 HTMLNodeList 对象）类型。
     *
     * @method isArrayLike
     * @param {*} val - 要检测是的数据
     * @returns {boolean} 'val' 是 array、arguments 或者 HTMLNodeList 类型返回 true，否则返回 false
     */
    function isArrayLike ( val ) {

        var type = typeOf( val );

        return type === TYPE_ARRAY || type === TYPE_ARGUMENTS || type === TYPE_COLLECTION;
    }

    /**
     * 检测测试数据是否为 arguments 对象
     *
     * @method isArguments
     * @param {*} val
     * @return {boolean}
     */
    function isArguments ( val ) {
        return typeOf( val ) === TYPE_ARGUMENTS;
    }

    /**
     * 检测测试数据是否为 ArrayBuffer 类型
     *
     * @method isArrayBuffer
     * @param {*} val
     * @return {boolean}
     */
    function isArrayBuffer ( val ) {
        return typeOf( val ) === TYPE_ARRAY_BUFFER;
    }

    /* ===== ES2017 Arrays ===== */
    function isInt8Array ( val ) {
        return typeOf( val ) === TYPE_INT8_ARRAY;
    }

    function isUint8Array ( val ) {
        return typeOf( val ) === TYPE_UNIT8_ARRAY;
    }

    function isUint8ClampedArray ( val ) {
        return typeOf( val ) === TYPE_UNIT8_CLAMPED_ARRAY;
    }

    function isInt16Array ( val ) {
        return typeOf( val ) === TYPE_INT16_ARRAY;
    }

    function isUint16Array ( val ) {
        return typeOf( val ) === TYPE_UNIT16_ARRYA;
    }

    function isInt32Array ( val ) {
        return typeOf( val ) === TYPE_INT32_ARRAY;
    }

    function isUint32Array ( val ) {
        return typeOf( val ) === TYPE_UNIT32_ARRAY;
    }

    function isFloat32Array ( val ) {
        return typeOf( val ) === TYPE_FLOAT32_ARRAY;
    }

    function isFloat64Array ( val ) {
        return typeOf( val ) === TYPE_FLOAT64_ARRAY;
    }

    /**
     * 检测测试数据是否为 Boolean 类型
     *
     * @method isBoolean
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Boolean 类型则返回 true，否则返回 false
     */
    function isBoolean ( val ) {
        return typeOf( val ) === TYPE_BOOLEAN;
    }

    /**
     * 检测测试数据是否为 null
     *
     * @method isNull
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 为 null 返回 true，否则返回 false
     */
    function isNull ( val ) {
        return typeOf( val ) === TYPE_NULL;
    }

    /**
     * 检测测试数据是否为 Number 类型
     *
     * @method isNumber
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Number 类型返回 true，否则返回 false
     */
    function isNumber ( val ) {
        return typeOf( val ) === TYPE_NUMBER;
    }

    /**
     * 检测测试数据是否是一个数字（只能是 number 类型或者 '123123' 这样的数字字符串）
     *
     * @method isNumeric
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是一个数字返回 true，否则返回false
     */
    function isNumeric ( val ) {

        // isNumeric is limited to strings and numbers
        // (primitives or objects) that can be coerced
        // to finite numbers (gh-2662)
        var type = typeOf( val );

        return ( type === TYPE_NUMBER || type === TYPE_STRING ) &&

            // parseFloat NaNs numeric-cast false positives ("")
            // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
            // subtraction forces infinities to NaN
            !isNaN( val - parseFloat( val ) );
    }

    /**
     * 检测测试数据是否为整数
     *
     * @method isInteger
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是整数返回 true，否则返回 false
     */
    function isInteger ( val ) {
        return isNumber( val ) && !isNaN( val ) && Number( val ) === val && val % 1 === 0;
    }

    /**
     * 检测测试数据是否为整数
     *
     * @method isFloat
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是整数返回 true，否则返回 false
     */
    function isFloat ( val ) {
        return isNumber( val ) && !isNaN( val ) && Number( val ) === val && val % 1 !== 0;
    }

    /**
     * 检测测试数据的数据类型是否为奇数
     *
     * @method isOdd
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是奇数返回 true，否则返回 false
     */
    function isOdd ( val ) {
        return isInteger( val ) && val % 2 !== 0;
    }

    /**
     * 检测测试数据的数据类型是否为偶数
     *
     * @method isEven
     * @param val - 要检测的数据
     * @returns {boolean} 'val' 是偶数返回 true，否则返回 false
     */
    function isEven ( val ) {
        return isInteger( val ) && val % 2 === 0;
    }

    /**
     * 检测测试数据的数据是正无穷或者负无穷
     *
     * @method isInfinite
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是正无穷或者负无穷返回 true，否则返回 false
     */
    function isInfinite ( val ) {
        return val === Infinity || val === -Infinity;
    }

    /**
     * 检测测试数据是否为字符串
     *
     * @method isString
     * @param {*} obj - 要检测的数据
     * @returns {boolean} 'val' 是字符串返回 true，否则返回 false
     */
    function isString ( obj ) {
        return typeOf( obj ) === TYPE_STRING;
    }

    /**
     * 检测测试数据是否为空字符串
     *
     * @method isEmpty
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是空字符串返回 true，否则返回 false
     */
    function isEmpty ( val ) {
        return val === '';
    }

    /**
     * 检测测试数据是否只包空格
     *
     * @method isBlank
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 只包含空格返回 true，否则返回 false
     */
    function isBlank ( val ) {

        if ( !isString( val ) ) {
            return false;
        }

        return /^\s*$/.test( val );
    }

    /**
     * 检测测试数据是否为一个基于 base64 编码的字符串。
     *
     * @param {*} val - 要检测的数据
     * @return {boolean} 'val' 是 base64 编码的字符串返回 true，否则返回 false
     */
    function isBase64 ( val ) {
        return isString( val ) && (!val.length || REGEXP_BASE64.test( val ));
    }

    /**
     * 检测测试数据是否为 16 进制编码的字符串
     *
     * @param val - 要检测的数据
     * @returns {boolean} 'val' 是 16 进制编码的字符串返回 true，否则返回 false
     */
    function isHex ( val ) {
        return isString( val ) && REGEXP_HEX.test( val );
    }

    /**
     * 检测测试数据是否为 JSON 格式字符串数据
     *
     * @method isJSON
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 JSON 格式字符串数据返回 true，否则返回 false
     */
    function isJSON ( val ) {

        if ( !isString( val ) || isBlank( val ) || !val ) {
            return false;
        }

        val = val.replace( /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@' );
        val = val.replace( /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']' );
        val = val.replace( /(?:^|:|,)(?:\s*\[)+/g, '' );

        return (/^[\],:{}\s]*$/).test( val );
    }

    /**
     * 检测测试数据是否为 Set 类型
     *
     * @method isSet
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Set 类型返回 true，否则返回 false
     */
    function isSet ( val ) {
        return typeOf( val ) === TYPE_SET;
    }

    /**
     * 检测测试数据是否为 WeakSet 类型
     *
     * @method isWeakSet
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 WeakSet 类型返回 true，否则返回 false
     */
    function isWeakSet ( val ) {
        return typeOf( val ) === TYPE_WEAKSET;
    }

    /**
     * 检测测试数据是否为 Map 类型
     *
     * @method Map
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Map 类型返回 true，否则返回 false
     */
    function isMap ( val ) {
        return typeOf( val ) === TYPE_MAP;
    }

    /**
     * 检测测试数据是否为 WeakMap 类型
     *
     * @method isWeakMap
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 WeakMap 类型返回 true，否则返回 false
     */
    function isWeakMap ( val ) {
        return typeOf( val ) === TYPE_WEAKMAP;
    }

    /**
     * 检测测试数据是否为 Symbol 类型
     *
     * @method isSymbol
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Symbol 类型返回 true，否则返回 false
     */
    function isSymbol ( val ) {
        return typeOf( val ) === TYPE_SYMBOL;
    }

    /**
     * 检测测试数据是否 undefined（未定义）
     *
     * @method isUndefined
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 undefined（未定义）返回 true，否则返回 false
     */
    function isUndefined ( val ) {
        return typeOf( val ) === TYPE_UNDEFINED;
    }

    /**
     * 检测测试数据是否为 Function 类型
     *
     * @method isFunction
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Function 类型返回 true，否则返回 false
     */
    function isFunction ( val ) {
        return typeOf( val ) === TYPE_FUNCTION;
    }

    /**
     * 检测测试函数是否为构造函数
     *
     * @method isConstructor
     * @param {function} fn - 要测试的（构造）函数
     * @returns {boolean} - fn 是构造函数返回 true，否则返回 false;
     */
    function isConstructor ( fn ) {
        var instance;

        if ( !isFunction ) {
            return false;
        }

        try{
            instance = new fn();
        }
        catch (err) {
            if (err.message.indexOf('is not a constructor')) {
                return false;
            }
        }

        return (instance.constructor === fn && instance instanceof fn) || (instance.constructor === Object && instance instanceof Object);
    }

    /**
     *  检测测试数据是否为构造函数
     *
     * @method isNativeFunction
     * @param {function} fn - 要测试的函数
     * @returns {boolean} - fn 是内置函数返回 true，否则返回 false;
     */
    function isNativeFunction ( fn ) {
        return isFunction( fn ) && (/\{\s*\[native code\]\s*\}/).test( '' + fn );
    }

    /**
     * 检测对象是否包含某个属性
     *
     * @method hasOwnProperty
     * @param {*} obj
     * @param {string} prop
     * @returns {boolean}
     * @private
     */
    function hasOwnProperty ( obj, prop ) {
        if ( OP.hasOwnProperty ) {
            return obj && obj.hasOwnProperty && obj.hasOwnProperty( prop );
        }
        else {
            return !isUndefined( obj[ prop ] ) && obj.constructor.prototype[ prop ] !== obj[ prop ];
        }
    }

    /**
     * 检测测试数据是否为对象
     *
     * @method isObject
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 为对象返回 true，否则返回 false
     */
    function isObject ( val ) {
        var type = typeOf( val );

        return (val && (type === TYPE_OBJECT || (type === TYPE_FUNCTION || isFunction( val )))) || false;
    }

    /**
     * 检测测试数据是否为普通对象
     *
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是普通对象返回 true，否则返回 false
     */
    function isPlainObject ( val ) {
        var proto,
            Ctor;

        // Detect obvious negatives
        if ( !val || !isObject( val ) ) {
            return false;
        }

        proto = val.prototype;

        // Objects with no prototype (e.g., `Object.create( null )`) are plain
        if ( !proto ) {
            return true;
        }

        // Objects with prototype are plain if they were constructed by a global Object function
        Ctor = hasOwnProperty( proto, 'constructor' ) && proto.constructor;

        return typeof Ctor === TYPE_FUNCTION && toString.toString.call( Ctor ) === {}.hasOwnProperty.toString.call( Object );
    }

    /**
     * 检测测试数据是否为空（单体）对象
     *
     * @method isEmptyObject
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是空对象返回 true，否则返回 false
     */
    function isEmptyObject ( val ) {

        /* eslint-disable no-unused-vars */
        // See https://github.com/eslint/eslint/issues/6125
        var prop;

        for ( prop in val ) {
            if ( hasOwnProperty( val, prop ) ) {
                return false;
            }
        }

        return true;
    }

    /**
     * 检测测试数据是否为 DataView 类型
     *
     * @method isDataView
     * @param {*} val
     * @return {boolean}
     */
    function isDataView ( val ) {
        return typeOf( val ) === TYPE_DATA_VIEW;
    }

    /**
     * 检测测试数据的数据类型是否为 Date 类型
     *
     * @method isDate
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 为 Date 类型返回 true，否则返回 false
     */
    function isDate ( val ) {
        return typeOf( val ) === TYPE_DATE && val.toString() !== 'Invalid Date' && !isNaN( val );
    }

    /**
     * 检测测试数据是否为正则表达式
     *
     * @method isRegExp
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是正则表达式返回 true，否则返回 false
     */
    function isRegExp ( val ) {
        return typeOf( val ) === TYPE_REGEXP;
    }

    /**
     * 检测测试数据的数据类型是否为 HTML 元素节点。
     *
     * @method isElement
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 为 HTML 元素节点返回 true，否则返回 false
     */
    function isElement ( val ) {
        return typeOf( val ) === TYPE_ELEMENT;
    }

    /**
     * 检测数据的是否为 HTMLNodeList 对象
     *
     * @method isHTMLCollection
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 HTMLNodeList 对象返回 true，否则返回 false
     */
    function isHTMLCollection ( val ) {
        return typeOf( val ) === TYPE_COLLECTION;
    }

    /**
     * 检测测试数据是否为文本节点
     *
     * @method isTextNode
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是文本节点返回 true，否则返回 false
     */
    function isTextNode ( val ) {
        return typeOf( val ) === TYPE_TEXT || typeOf( val ) === TYPE_WHITESPACE;
    }

    /**
     * 检测是否为 XML 文档
     *
     * @param {*} val
     * @returns {boolean}
     */
    function isXML ( val ) {

        var documentElement = val && (val.ownerDocument || val).documentElement;
        return documentElement ? documentElement.nodeName !== 'HTML' : false;
    }

    /**
     * 检测测试数据是否为 Error 类型
     *
     * @method isError
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是 Error 类型返回 true，否则返回 false
     */
    function isError ( val ) {
        return typeOf( val ) === TYPE_ERROR;
    }

    /**
     * 检测测试数据是否为有效的数据
     *
     * @method isValue
     * @param {*} val - 要检测的数据
     * @returns {boolean} 'val' 是有效的数据返回 true，否则返回 false
     */
    function isValue ( val ) {
        var type = typeOf( val );

        switch ( type ) {
            case TYPE_NUMBER:
                return isFinite( val );

            case TYPE_NULL:
            case TYPE_UNDEFINED:
                return false;

            default:
                return !!type;
        }
    }

    var typeofit = {
        is: typeOf,
        isArray: isArray,
        isArrayLike: isArrayLike,
        isArguments: isArguments,
        isArrayBuffer: isArrayBuffer,
        isInt8Array: isInt8Array,
        isUint8Array: isUint8Array,
        isUint8ClampedArray: isUint8ClampedArray,
        isInt16Array: isInt16Array,
        isUint16Array: isUint16Array,
        isInt32Array: isInt32Array,
        isUint32Array: isUint32Array,
        isFloat32Array: isFloat32Array,
        isFloat64Array: isFloat64Array,
        isBase64: isBase64,
        isBlank: isBlank,
        isBoolean: isBoolean,
        isConstructor: isConstructor,
        isDataView: isDataView,
        isDate: isDate,
        isElement: isElement,
        isEmpty: isEmpty,
        isEmptyObject: isEmptyObject,
        isError: isError,
        isEven: isEven,
        isFloat: isFloat,
        isFunction: isFunction,
        isHash: isPlainObject,
        isHex: isHex,
        isHTMLCollection: isHTMLCollection,
        isInfinite: isInfinite,
        isInteger: isInteger,
        isJSON: isJSON,
        isMap: isMap,
        isNativeFunction: isNativeFunction,
        isNull: isNull,
        isNumber: isNumber,
        isNumeric: isNumeric,
        isObject: isObject,
        isOdd: isOdd,
        isPlainObject: isPlainObject,
        isRegExp: isRegExp,
        isSet: isSet,
        isString: isString,
        isSymbol: isSymbol,
        isTextNode: isTextNode,
        isUndefined: isUndefined,
        isValue: isValue,
        isWeakMap: isWeakMap,
        isWeakSet: isWeakSet,
        isXML: isXML
    };

    if ( !isUndefined( global ) ) {
        global.typeofit = typeofit;
    }
    else {
        if ( isObject( module ) && isObject( module.exports ) ) {

            // AMD
            module.exports = typeofit;
        }
        else {

            // CMD
            if ( isFunction( define ) && define.cmd ) {
                define( function ( require, exports, module ) {
                    module.exports = typeofit;
                } );
            }
        }
    }
})();